package orm

import (
	"orm/internal/errs"
	"strings"
)

var (
	DialectMySQL   Dialect = mysqlDialect{}
	DialectSQLLite Dialect = sqlliteDialect{}
	DialectPostgre Dialect = postgreDialect{}
)

type Dialect interface {
	// quoter 就是为了解决引号问题
	quoter() byte
	buildUpsert(b *builder, upsert *Upsert) error
}

type standardSQL struct {
}

func (s standardSQL) quoter() byte {
	//TODO implement me
	panic("implement me")
}

func (s standardSQL) buildOnDuplicateKey(sb strings.Builder, upsert *Upsert) error {
	//TODO implement me
	panic("implement me")
}

type mysqlDialect struct {
	standardSQL
}

func (s mysqlDialect) buildUpsert(b *builder, upsert *Upsert) error {
	b.sb.WriteString(" ON DUPLICATE KEY UPDATE ")
	for idx, assign := range upsert.assigns {
		if idx > 0 {
			b.sb.WriteByte(',')
		}
		switch a := assign.(type) {
		case Assignment:
			fd, ok := b.model.FieldsMap[a.col]
			if !ok {
				return errs.NewErrUnknownField(a.col)
			}
			b.quote(fd.ColName)
			b.sb.WriteString("=?")
			b.args = append(b.args, a.val)
		case Column:
			fd, ok := b.model.FieldsMap[a.name]
			if !ok {
				return errs.NewErrUnknownField(a.name)
			}
			b.quote(fd.ColName)
			b.sb.WriteString("=VALUES(")
			b.quote(fd.ColName)
			b.sb.WriteByte(')')

		default:
			return errs.NewErrUnsupportedAssignable(assign)
		}
	}
	return nil
}

func (s mysqlDialect) quoter() byte {
	return '`'
}

type sqlliteDialect struct {
	standardSQL
}

func (s sqlliteDialect) quoter() byte {
	return '`'
}

func (s sqlliteDialect) buildUpsert(b *builder, upsert *Upsert) error {
	b.sb.WriteString(" ON CONFLICT(")
	for i, col := range upsert.conflictColumns {
		if i > 0 {
			b.sb.WriteByte(',')
		}
		err := b.buildColumn(col)
		if err != nil {
			return err
		}

	}
	b.sb.WriteString(") DO UPDATE SET ")
	for idx, assign := range upsert.assigns {
		if idx > 0 {
			b.sb.WriteByte(',')
		}
		switch a := assign.(type) {
		case Assignment:
			fd, ok := b.model.FieldsMap[a.col]
			if !ok {
				return errs.NewErrUnknownField(a.col)
			}
			b.quote(fd.ColName)
			b.sb.WriteString("=?")
			b.args = append(b.args, a.val)
		case Column:
			fd, ok := b.model.FieldsMap[a.name]
			if !ok {
				return errs.NewErrUnknownField(a.name)
			}
			b.quote(fd.ColName)
			b.sb.WriteString("=excluded.")
			b.quote(fd.ColName)

		default:
			return errs.NewErrUnsupportedAssignable(assign)
		}
	}
	return nil
}

type postgreDialect struct {
	standardSQL
}

func (p postgreDialect) buildUpsert(b *builder, upsert *Upsert) error {
	//TODO implement me
	panic("implement me")
}
